package main

import (
	"database/sql"
	"errors"
	_ "github.com/go-sql-driver/mysql"
	"time"
)

// ReResultsByList 以LIST方式返回结果
type ReResultsByList struct {
	ExecState error
	ReData    [][]string
	ExecCost  time.Duration
	ColsNum   int64
	RowsNum   int64
}

func OpenDB(dbDsn string) (error, *sql.DB) {
	var sitkDB *sql.DB
	var err error
	sitkDB, err = sql.Open("mysql", dbDsn)
	if err != nil {
		return err, nil
	}
	err = sitkDB.Ping()
	if err != nil {
		return errors.New("数据库通讯错误 " + err.Error()), nil
	}
	sitkDB.SetMaxOpenConns(10)
	sitkDB.SetMaxIdleConns(2)
	sitkDB.SetConnMaxLifetime(time.Duration(20) * time.Second)
	return nil, sitkDB
}

func CloseDB(dbObj *sql.DB) error {
	var err error
	err = dbObj.Close()
	return err
}

// GetRowByList 获取多行多列数据,以List形式返回
func GetRowByList(sitkDB *sql.DB, queryString string, queryArgs ...any) ReResultsByList {
	var reData ReResultsByList
	var err error
	var rows *sql.Rows
	starTime := time.Now()
	rows, err = sitkDB.Query(queryString, queryArgs...)
	if err != nil {
		reData.ExecState = err
		reData.ExecCost = time.Since(starTime)
		return reData
	}
	//获取列名字段
	defer func(rows *sql.Rows) {
		_ = rows.Close()
	}(rows)
	var colNames []string
	colNames, err = rows.Columns()
	if err != nil {
		reData.ExecState = err
		reData.ExecCost = time.Since(starTime)
		return reData
	}
	var colLength int
	colLength = len(colNames)
	reData.ColsNum = int64(colLength)
	reData.ReData = append(reData.ReData, colNames)

	//values是每个列的值，这里获取到byte里
	values := make([][]byte, colLength)
	//Scan的参数，因为每次查询出来的列是不定长的，用colLength作为当次查询的长度
	scans := make([]interface{}, colLength)
	//让每一行数据都填充到[][]byte里面
	for i := range values {
		scans[i] = &values[i]
	}
	//获取每一行数据
	reData.RowsNum = 0
	rowData := make([]string, 0)
	for rows.Next() {
		err = rows.Scan(scans...)
		if err != nil {
			reData.ExecState = err
			break
		}

		for _, v := range values {
			rowData = append(rowData, string(v))
		}
		reData.ReData = append(reData.ReData, rowData)
		reData.RowsNum++
		rowData = []string{}
	}
	reData.ExecCost = time.Since(starTime)
	return reData
}
